import 'package:family_expense/features/income_expense/constants/payment_type.dart';
import 'package:family_expense/features/income_expense/models/income_expense_detail.dart';
import 'package:family_expense/features/income_expense/models/income_expense_detail_summary.dart';
import 'package:family_expense/features/income_expense/services/income_expense_detail_service.dart';
import 'package:family_expense/features/income_expense/widgets/income_expense_detail_shared.dart';
import 'package:family_expense/features/income_expense/widgets/income_expense_detail_view.dart';
import 'package:flutter/material.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:my_flutter_core/my_flutter_core.dart';

/// To make [PagingListViewLoadController] work to reset the list the widget must be stateful.
class HomeView extends StatefulWidget {
  const HomeView({super.key});

  @override
  State<HomeView> createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView> {
  final int _pageSize = GeneralConfig.listViewPageSize;

  // Retrieves income/expense list.
  final IncomeExpenseDetailService _incomeExpenseDetailService =
      IncomeExpenseDetailService();

  // Stores the month summary days to avoid duplicate info when building the list.
  // Because the server returns data might contain multiple items with same month summary info.
  final Map<String?, DateTime?> _monthSummaryDays = {};

  // Stores the day summary days to avoid duplicate info when building the list.
  // Because the server returns data might contain multiple items with same day summary info.
  final Map<String?, DateTime?> _daySummaryDays = {};

  // Used to reset the list once the income/expense detail updated.
  late PagingListViewLoadController _loadController;

  @override
  Widget build(BuildContext context) {
    return PagingListView(
      padding: const EdgeInsets.only(top: 10.0, bottom: 80.0),
      pageSize: _pageSize,
      getLoadController: (loadController) => _loadController = loadController,
      retrieveData: (pageIndex) => _incomeExpenseDetailService
          .queryListWithSummaryByAccountGroup(_pageSize, pageIndex!),
      itemBuilder: (context, entry, index) {
        final item = entry as IncomeExpenseDetail;

        // If month summary or day summary data exists.
        if (item.monthSummary != null || item.daySummary != null) {
          final children = <Widget>[];

          // More than one items might contain month summary due to pagination. We cannot add duplicate month summary.
          // Checking on [containsValue] makes sure the month summary has not been added yet.
          //
          // Also the list view items will be created and re-created during scrolling. We also need to add the summary once the item is re-creating.
          // [containsKey] means this item already has been created before. If this is called again that means this item is re-creating.
          if (item.monthSummary != null &&
              (!_monthSummaryDays.containsValue(
                    item.monthSummary!.incomeExpenseDate,
                  ) ||
                  _monthSummaryDays.containsKey(item.id))) {
            children.add(
              _buildMonthSummary(context, item.id!, item.monthSummary!),
            );
          }

          // If day summary data exists and it's not been add yet.
          // Same reason as above.
          if (item.daySummary != null &&
              (!_daySummaryDays.containsValue(
                    item.daySummary!.incomeExpenseDate,
                  ) ||
                  _daySummaryDays.containsKey(item.id))) {
            children.add(_buildDaySummary(context, item.id!, item.daySummary!));
          }

          // Adds the detail item.
          children.add(_buildDetail(item));

          return Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: children,
          );
        } else {
          return _buildDetail(item);
        }
      },
    );
  }

  /// Builds the detail list tile.
  Widget _buildDetail(IncomeExpenseDetail item) {
    return IncomeExpenseDetailListTile(item, () async {
      final dataUpdated = await NavigatorHelper.push<bool>(
        context,
        IncomeExpenseDetailView(item.id!),
      );

      // If the income/expense details is updated we need to refresh the list.
      if (dataUpdated == true) {
        _daySummaryDays.clear();
        _monthSummaryDays.clear();
        _loadController.reset();
      }
    });
  }

  /// Builds the month summary section.
  Widget _buildMonthSummary(
    BuildContext context,
    String detailId,
    IncomeExpenseDetailSummary monthSummary,
  ) {
    _monthSummaryDays[detailId] = monthSummary.incomeExpenseDate;

    return ExpansionTile(
      title: Text(
        monthSummary.incomeExpenseDate.formatDate(DatePatterns.yearMonth),
        style: const TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold),
      ),
      children: [
        Padding(
          padding: const EdgeInsets.only(left: 20.0, right: 20.0, bottom: 10.0),
          child: _buildSummary(monthSummary),
        ),
      ],
    );
  }

  /// Builds the day summary section.
  Widget _buildDaySummary(
    BuildContext context,
    String detailId,
    IncomeExpenseDetailSummary daySummary,
  ) {
    _daySummaryDays[detailId] = daySummary.incomeExpenseDate;

    return Container(
      color: const Color.fromRGBO(242, 242, 242, 1.0),
      child: ExpansionTile(
        title: Text(
          daySummary.incomeExpenseDate!.convertDateToFriendlyText(
            DatePatterns.shortDate,
          ),
          style: const TextStyle(fontSize: 14.0),
        ),
        children: [
          Padding(
            padding: const EdgeInsets.only(
              left: 20.0,
              right: 20.0,
              bottom: 10.0,
            ),
            child: _buildSummary(daySummary),
          ),
        ],
      ),
    );
  }

  /// Builds income/expense/balance summary of cash/credit card.
  Widget _buildSummary(IncomeExpenseDetailSummary summary) {
    const numberTextStyle = TextStyle(fontSize: 14.0);
    const iconSize = 16.0;

    final balanceNumberTextStyle = numberTextStyle.copyWith(
      fontWeight: FontWeight.bold,
    );

    return Row(
      children: [
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            IncomeExpenseDetailShared.getTypeIcon(
              PaymentType.cash,
              size: iconSize,
            )!,
            IncomeExpenseDetailShared.getTypeIcon(
              PaymentType.creditCard,
              size: iconSize,
            )!,
            Icon(MdiIcons.bellOutline, size: iconSize),
          ],
        ),
        const SizedBox(width: 10.0),
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                '${formatNumber(summary.cashIncome)} - ${formatNumber(summary.cashExpense!.abs())}',
                style: numberTextStyle,
              ),
              Text(
                '${formatNumber(summary.creditCardIncome)} - ${formatNumber(summary.creditCardExpense!.abs())}',
                style: numberTextStyle,
              ),
              Text(
                '${formatNumber(summary.cashIncome! + summary.creditCardIncome!)} - ${formatNumber(summary.cashExpense!.abs() + summary.creditCardExpense!.abs())}',
                style: numberTextStyle,
              ),
            ],
          ),
        ),
        Column(
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            Text(
              formatBalanceNumber(summary.cashBalance),
              style: balanceNumberTextStyle.copyWith(
                color: IncomeExpenseDetailShared.getAmountColor(
                  summary.cashBalance,
                ),
              ),
            ),
            Text(
              formatBalanceNumber(summary.creditCardBalance),
              style: balanceNumberTextStyle.copyWith(
                color: IncomeExpenseDetailShared.getAmountColor(
                  summary.creditCardBalance,
                ),
              ),
            ),
            Text(
              formatBalanceNumber(
                summary.cashBalance! + summary.creditCardBalance!,
              ),
              style: balanceNumberTextStyle.copyWith(
                color: IncomeExpenseDetailShared.getAmountColor(
                  summary.cashBalance! + summary.creditCardBalance!,
                ),
              ),
            ),
          ],
        ),
      ],
    );
  }
}
